Skip to main content

Switching networks

When building a dApp that works across multiple chains you might want to send a transaction on one chain while the user has a different chain selected in their wallet.

You could prompt the user to switch a network using the switchNetwork function:

const { switchNetwork, chainId } = useEthers()

const sendTransaction = async () => {
if(chainId !== Mainnet.chainId) {
await switchNetwork(Mainnet.chainId)
}

// ...send a transaction on mainnet
}

If the user has metamask installed they would see the following prompt:

metamask-switch-network

Example

App.tsx
import React from 'react'
import ReactDOM from 'react-dom'
import { DAppProvider, useSendTransaction, useEthers, Config, Goerli, Mainnet, Optimism } from '@usedapp/core'
import { getDefaultProvider } from 'ethers'

const config: Config = {
readOnlyChainId: Mainnet.chainId,
readOnlyUrls: {
[Mainnet.chainId]: getDefaultProvider('mainnet'),
[Optimism.chainId]: getDefaultProvider('optimism'),
[Goerli.chainId]: getDefaultProvider('goerli'),
},
}

ReactDOM.render(
<DAppProvider config={config}>
<App />
</DAppProvider>,
document.getElementById('root')
)

export function App() {
const { chainId, switchNetwork, activateBrowserWallet, account } = useEthers()
const { sendTransaction, state } = useSendTransaction()

const status = state.status
const address = '0xe13610d0a3e4303c70791773C5DF8Bb16de185d1'

const send = () => {
void sendTransaction({ to: address, value: 1 })
}

const WalletContent = () => (
<>
<div>Current chain: {chainId}</div>
<div>
{
<button onClick={() => switchNetwork(Mainnet.chainId)} disabled={chainId === Mainnet.chainId}>
Switch to Mainnet
</button>
}{' '}
{
<button onClick={() => switchNetwork(Optimism.chainId)} disabled={chainId === Optimism.chainId}>
Switch to Optimism
</button>
}{' '}
{
<button onClick={() => switchNetwork(Goerli.chainId)} disabled={chainId === Goerli.chainId}>
Switch to Goerli
</button>
}
</div>
<hr />
<div>
<div>Account: {account ?? 'not connected'}</div>
<button onClick={() => send()}>Send ether</button>
<p>Status: {status}</p>
{state.errorMessage && <p>Error: {state.errorMessage}</p>}
</div>
</>
)

return (
<div>
{!account && <button onClick={() => activateBrowserWallet()}>Connect</button>}
{account ? <WalletContent /> : <p>Connect to wallet to interact with the example.</p>}
</div>
)
}

Troubleshooting

You might encounter these known errors thrown when using switchNetwork:

  • Error: ChainId "xyz" does not have RPC url configured by default.

It means that there the network you are trying to switch to is known, but there is no stable public RPC endpoint configured in useDApp. Known networks are listed here.

Here is an example of a chain with known public RPC.

Here is an example of a chain, which (at the time) did not have an RPC endpoint included in useDApp.

Because of missing RPC endpoint, switchNetwork will throw this error because a network cannot be added automatically to a browser Wallet without an RPC endpoint.

Solution

If you have an RPC endpoint, you can supply it to useDApp config.

Assuming we're working with Polygon without rpcUrl:

import { Config, Polygon, DEFAULT_SUPPORTED_CHAINS } from '@usedapp/core'

const myNetworks = [...DEFAULT_SUPPORTED_CHAINS]
const polygon = myNetworks.find(chain => chain.chainId === Polygon.chainId)
polygon.rpcUrl = 'https://polygon-rpc.com/'

const config: Config = {
...
networks: myNetworks
}
  • Error: ChainId "xyz" not found in config.networks.

It means that the chain in question is not known to useDApp. You would have to provide the configuration yourself.

For that, see the following instructions: Include your custom chain in Config.